// file:include/os/elf32.h
// autor:jiangxinpeng
// time:2021.4.15
// copyright:(C) by jiangxinpeng,All right are reserved.

#ifndef OS_ELF32_H
#define OS_ELF32_H

#include <lib/type.h>

#define ELF_PHMAX 256

typedef uint32_t Elf32_Word, Elf32_Addr, Elf32_Off;
typedef uint16_t Elf32_Half;

// elf32 program header table
// segment descript table
#pragma pack(push, 1)
typedef struct
{
    Elf32_Word p_type;     // the type of segment current descript by programe header
    Elf32_Off p_offset;    // segment first bytes offset
    Elf32_Addr p_vaddr;    // virtual address
    Elf32_Addr p_paddr;    // pyhics address
    Elf32_Word p_filesize; // filesize of segment in file
    Elf32_Word p_memsize;  // memsize of segment
    Elf32_Word p_flags;    // segment flags
    Elf32_Word p_align;    // segment aligned;
} elf32_segment_t;
#pragma pack(pop)

#pragma pack(push, 1)
typedef struct
{
    Elf32_Word s_name;    // section name index
    Elf32_Word s_type;    // section type
    Elf32_Word s_flags;   // section flags
    Elf32_Addr s_addr;    // section first byte addr
    Elf32_Off s_offset;   // section first byte offset
    Elf32_Word s_size;    // section size
    Elf32_Word s_link;    // section link
    Elf32_Word s_info;    // section info
    Elf32_Word s_aligned; // section aligned
    Elf32_Word s_ensize;  // section size
} elf32_section_t;
#pragma pack(pop)

#pragma pack(push, 1)
typedef struct
{
    uint8_t MAGIC[4]; // ELF
    uint8_t class;    // 1:bits32 2:bits64
    uint8_t endian;   // 1:little endian 2: big endian
    uint8_t version;  // efi version
    uint8_t OSABI;    // unknow
    uint8_t unuse[8];
} elf32_ident_t;
#pragma pack(pop)

// elf32 header
#pragma pack(push, 1)
typedef struct Elf32_Header
{
    elf32_ident_t e_ident;
    Elf32_Half e_type;
    Elf32_Half e_machie;
    Elf32_Word e_verison;
    Elf32_Addr e_entry;
    Elf32_Off e_phoff;
    Elf32_Off e_shoff;
    Elf32_Word e_flags;
    Elf32_Half e_ehsize;
    Elf32_Half e_phensize;
    Elf32_Half e_phnum;
    Elf32_Half e_shensize;
    Elf32_Half e_shnum;
    Elf32_Half e_shstrndx;
} elf32_header_t;
#pragma pack(pop)

// elf32 class
enum elf32_class
{
    ELF_CLASSUNKNOW = 0, // unknow class
    ELF_CLASS32,         // bits 32
    ELF_CLASS64,         // bits 64
};

// elf32 endian
enum elf32_endian
{
    ELF_ENDIANLITTLE = 1,
    ELF_ENDIANBIG = 2,
};

enum elf32_osabi
{
    ELF_OSABI_NONE = 0,     // UNIX System V ABI
    ELF_OSABI_SYSV = 0,     // Alias
    ELF_OSABI_HPUX = 1,     // HP_UX
    ELF_OSABI_NETBSD = 2,   // NetBSD
    ELF_OSABI_LINUX = 3,    // Linux
    ELF_OSABI_SOLARIS = 6,  // Sun Solaris
    ELF_OSABI_AIX = 7,      // IBM AIX
    ELF_OSABI_IRIX = 8,     // SGI IRIX
    ELF_OSABI_FREEBSD = 9,  // FreeBSD
    ELF_OSABI_TRU64 = 10,   // Compaq TRU64 UNIX
    ELF_OSABI_MODESTO = 11, // Novell Modesto
    ELF_OSABI_OPENBSD = 12, // OpenBSD
    ELF_OSABI_ARM = 97,     // ARM
    ELF_OSABI_STANDALONE = 255,
};

enum elf32_version
{
    ELF_VERSION_INVAILD = 0, // invaild version
    ELF_VERSION_CURRENT = 1, // current version
    ELF_VERSION_NUM = 2
};

#define ElF_ABI_VERSION 0 // ABI version

// elf32 machine
enum elf32_machine
{
    ELF_ARCHUNKNOW = 0,
    ELF_SPARC = 2,
    ELF_X86 = 3,
    ELF_MIPS = 8,
    ELF_POWERPC = 0x14,
    ELF_ARM = 0x28,
    ELF_SUPERH = 0x2A,
    ELF_IA_64 = 0x32,
    ELF_X86_64 = 0x3E,
    ELF_AARCH64 = 0xB7
};

// elf header type
enum elfheader_type
{
    ELFTYPE_NONE = 0,
    ELFTYPE_REL,  // relocationable file
    ELFTYPE_EXEC, // executable file
    ELFTYPE_DYNC, // dyncmic share object file
    ELFTYPE_CORE, // core dumps
};

// elf segment type
enum elfsegment_type
{
    SEGTYPE_NULL,     // null
    SEGTYPE_LOAD,     // loadable program segment
    SEGTYPE_DYNAMIC,  // dynamic loader info
    SEGTYPE_INTERP,   // dynamic loader name
    SEGTYPE_NOTE,     // some note inof
    SEGTYPE_PROHEAD,  // program header table
    SEGTYPE_SHARELIB, // share libary
};

enum elfsection_type
{
    SECTIONTYPE_NULL = 0,                 // invalid section
    SECTIONTYPE_PROGBITS = 1,             // program data
    SECTIONTYPE_SYMTAB = 2,               // symbol table
    SECTIONTYPE_STRING = 3,               // string section
    SECTIONTYPE_RELA = 4,                 // relocationable section
    SECTIONTYPE_HASH = 5,                 // symbol hash table
    SECTIONTYPE_DYNAMIC = 6,              // dynamic link section
    SECTIONTYPE_NOTE = 7,                 // info
    SECTIONTYPE_NOBITS = 8,               // unused
    SECTIONTYPE_REL = 9,                  // relocationable
    SECTIONTYPE_SHLIB = 10,               // unused
    SECTIONTYPE_DYNSYM = 11,              // dynamic link symbol table
    SECTIONTYPE_LOPPROCDOWN = 0x70000000, // reservered to processor
    SECTIONTYPE_LOPPROCUP = 0x7fffffff,
    SECTIONTYPE_LOUSERDOWN = 0x80000000,
    SECTIONTYPE_LOUSERUP = 0x8fffffff
};

enum elfsection_flags
{
    SECTIONFLAGS_WRITE = 0x1,     // data write
    SECTIONFLAGS_ALLOC = 0x2,     // need alloc memory
    SECTIONFLAGS_EXECINSTR = 0x4, // contain excutable instruction
    SECTIONFLAGS_STRINGS = 0x6,   // string
    SECTIONFLAGS_MASKOS = 0x0ff00000,
    SECTIONFLAGS_MASKPROC = 0xf0000000,
};

#define ELF32_PE_X (1 << 0)          // executble
#define ELF32_PE_W (1 << 1)          // writeable
#define ELF32_PE_R (1 << 2)          // readable
#define ELF32_PE_OSMASK 0x0ff0000    // os specific
#define ELF32_PE_PROCMASK 0xf0000000 // process specific

#define ELF32_SEGMENT_CODE (ELF32_PE_X | ELF32_PE_R)                      // code segment
#define ELF32_SEGMENT_DATA (ELF32_PE_W | ELF32_PE_R)                      // data segment
#define ELF32_SEGMENT_CODE_DATA (ELF32_SEGMENT_CODE | ELF32_SEGMENT_DATA) // data segment

#endif